/**

 @Name : jQuery 日期选择插件
 @Author: mtr
 @Site：https://gitee.com/zhao_rui_rui/td-calendar-wrap
 @License：MIT

 */

;(function ($, window, document, undefined) {
    'use strict';

    var util = {
        // 创建元素
        elem: function (elemName, attr) {
            var elem = document.createElement(elemName);
            $.each(attr || {}, function (key, value) {
                elem.setAttribute(key, value);
            });
            return $(elem);
        },
        // 得到某月的最后一天
        getEndDay: function (month, year) {
            var thisDate = new Date();
            //设置日期为下个月的第一天
            thisDate.setFullYear(
                year || thisDate.getFullYear()
                , month || (thisDate.getMonth() + 1)
                , 1);
            //减去一天，得到当前月最后一天
            return new Date(thisDate.getTime() - 1000 * 60 * 60 * 24).getDate();
        },
        // 数字前置补零
        digit: function (num, length) {
            var str = '';
            num = String(num);
            length = length || 2;
            for (var i = num.length; i < length; i++) {
                str += '0';
            }
            return num < Math.pow(10, length) ? str + (num | 0) : num;
        },
        // 获取日期对象
        getDateObj: function (dateSource) {
            var date;
            if (typeof dateSource === "string") {
                date = new Date(dateSource.replace(/-/g,"/"));
            } else if (typeof dateSource === "object") {
                date = dateSource;
            } else {
                date = new Date();
            }
            var dateObj = {};
            dateObj.year = date.getFullYear();
            dateObj.mouth = date.getMonth() + 1;
            dateObj.yearMouth = dateObj.year + "-" + util.digit(dateObj.mouth, 2);
            dateObj.day = date.getDate();
            dateObj.week = date.getDay();
            dateObj.date = dateObj.yearMouth + "-" + util.digit(dateObj.day, 2);
            dateObj.time = date.getTime();
            return dateObj;
        },
        // 获取当月的日期列表
        getDateListByMouth: function (mouth, year) {
            var dateList = [];
            var endDay = util.getEndDay(mouth, year);
            for (let day = 1; day <= endDay; day++) {
                var date = year + "-" + util.digit(mouth, 2) + "-" + util.digit(day, 2);
                var dateObj = util.getDateObj(date + " 00:00:00");
                if (day === 1 && dateObj.week > 0) {
                    // 如果第一天不是周天 则补全至周天
                    for (let w = 0; w < dateObj.week; w++) {
                        dateList.push({
                            week: w
                        });
                    }
                }
                dateList.push(dateObj);
                if (day === endDay && dateObj.week < 6) {
                    // 如果最后一天不是周六 则补全至周六
                    for (let w = dateObj.week + 1; w < 7; w++) {
                        dateList.push({
                            week: w
                        });
                    }
                }
            }
            return dateList;
        },
    };

    var nowDate = new Date(),
        // 默认开始时间 现在
        defaultStartDate = util.getDateObj(nowDate),
        // 默认结束时间 一年后
        defaultEndDate = util.getDateObj(new Date(nowDate.getTime() + 1000 * 60 * 60 * 24 * 365));

    // 常量
    const CALENDAR_WRAP_CLASS = "tdCalendarWrap", // 可选的日期样式
        OPTIONAL_DATE_CLASS = "yesChoice", // 可选的日期样式
        SELECTED_DATE_CLASS = "active",  // 选中的日期样式
        BAN_SELECTED_DATE_CLASS = "noChoice";  // 不可选的日期样式

    var TdCalendarWrap = function (elem, config) {
        this.config = config;
        this.$elem = $(elem);
        this.$elem_source = this.$elem.clone();

        this.$elem.addClass(CALENDAR_WRAP_CLASS);
        this.init();
    };

    // 默认配置
    TdCalendarWrap.DEFAULT_CONFIG = {
        // 已选择的日期 初始化值
        selectedDate: [],
        // 最大选择数量
        selectedSizeMax: 6,
        // 可选择的日期 null 表示都可选
        optionalDate: null,
        // 默认日期配置
        optionalDateConfig: {
            // 中间显示的字的key 默认为天数
            textKey: "day",
            // 上面展示的字
            upText: "",
            // 选择后上面展示的字
            selectUpText: "",
            // 下面展示的字
            downText: "",
            // 选择后下面展示的字
            selectDownText: "",
        },
        // 显示开始月份
        showStartYearMouth: "",
        // 显示结束月份 默认一年
        showEndYearMouth: "",
        // 是否显示今天文字
        isShowTodayText: true,
        // 当选择后执行的回调
        // clickDate 当前点击的日期对象
        // selectedDate 全部选择的日期列表
        // elem 点击的dom元素
        done: function (clickDate, selectedDate, elem) {
        },
        // 当选择数量超过后的回调后执行的回调
        // clickDate 当前点击的日期对象
        // selectedSize 已选择的数量
        // elem 点击的dom元素
        selectedSizeExceed: function (clickDate, selectedSize, elem) {
            console.log("最多选择" + selectedSize + "个日期");
        }
    };

    // 默认日期配置
    TdCalendarWrap.DEFAULT_DATE_CONFIG = {
        // 当前是否可选
        optional: false,
        // 当前是否选中
        selected: false,
        // 中间显示的字的key 默认为天数
        textKey: "day",
        // 上面展示的字
        upText: "",
        // 选择后上面展示的字
        selectUpText: "",
        // 下面展示的字
        downText: "",
        // 选择后下面展示的字
        selectDownText: "",
    };

    // 插件初始化
    TdCalendarWrap.prototype.init = function () {
        this.initConfig();
        this.initHeaderWeekList();
        this.initCalendarInfo();
    };

    // 初始化头部周列表
    TdCalendarWrap.prototype.initConfig = function () {
        var optionalDate = this.config.optionalDate;
        var optionalDateMap = {}, showStartYearMouth, showEndYearMouth, isAllOptional;
        if (optionalDate && optionalDate.length > 0) {
            isAllOptional = false;
            optionalDate.forEach(function (item, index) {
                var date;
                if (typeof item === "string") {
                    date = util.getDateObj(item + " 00:00:00");
                } else if (typeof item === "object") {
                    var dateObj = util.getDateObj(item.date + " 00:00:00");
                    date = $.extend({}, dateObj, item);
                }
                if (date) {
                    // 设置为可选
                    date.optional = true;
                    optionalDateMap[date.date] = date;
                    // 设置最小年月
                    if (!showStartYearMouth || date.yearMouth < showStartYearMouth) {
                        showStartYearMouth = date.yearMouth;
                    }
                    // 设置最大年月
                    if (!showEndYearMouth || date.yearMouth > showEndYearMouth) {
                        showEndYearMouth = date.yearMouth;
                    }
                }
            });
        } else {
            isAllOptional = true;
            // 显示开始月份
            showStartYearMouth = defaultStartDate.year + "-" + util.digit(defaultStartDate.mouth, 2);
            // 显示结束月份 默认一年
            showEndYearMouth = defaultEndDate.year + "-" + util.digit(defaultEndDate.mouth, 2);
        }
        this.config.isAllOptional = isAllOptional;
        this.config.optionalDateMap = optionalDateMap;
        if (!this.config.showStartYearMouth) {
            this.config.showStartYearMouth = showStartYearMouth;
        }
        if (!this.config.showEndYearMouth) {
            this.config.showEndYearMouth = showEndYearMouth;
        }
        var selectedDate = [];
        this.config.selectedDate.forEach(function (date, index) {
            if (Object.keys(optionalDateMap).length > 0) {
                if (optionalDateMap[date]) {
                    selectedDate.push(date);
                }
            } else {
                // 为空表示全选 直接添加
                selectedDate.push(date);
            }
        });
        this.selectedDate = selectedDate;
    };

    // 初始化头部周列表
    TdCalendarWrap.prototype.initHeaderWeekList = function () {
        this.$weekList = $([
            '<div class="weekList">',
            '    <span class="weekItem restDay">日</span>',
            '    <span class="weekItem">一</span>',
            '    <span class="weekItem">二</span>',
            '    <span class="weekItem">三</span>',
            '    <span class="weekItem">四</span>',
            '    <span class="weekItem">五</span>',
            '    <span class="weekItem restDay">六</span>',
            '</div>',
        ].join(''));
        this.$elem.append(this.$weekList);
    };

    // 初始化日历信息
    TdCalendarWrap.prototype.initCalendarInfo = function () {
        this.$calendarInfo = $('<div class="calendarInfo"></div>');
        this.$elem.append(this.$calendarInfo);
        this.mouthList = [];
        var showStartYearMouth = this.config.showStartYearMouth + "-01 00:00:00";
        var currentDate = new Date(showStartYearMouth.replace(/-/g,"/"));
        var showEndYearMouth = this.config.showEndYearMouth;

        while (true) {
            var currentDateObj = util.getDateObj(currentDate);
            // 添加这个月的天
            this.addOneMouthInfo(currentDateObj);
            if (currentDateObj.yearMouth === showEndYearMouth) {
                break;
            }
            // 月份加一
            currentDate.setMonth(currentDate.getMonth() + 1);
        }
    };

    // 在日历添加一月显示
    TdCalendarWrap.prototype.addOneMouthInfo = function (dateObj) {
        var mouthElem = $('<div class="calendarItem"></div>'),
            yearMonth = $('<div class="yearMonth">' + dateObj.year + '年' + dateObj.mouth + '月</div>'),
            dayListBox = $('<div class="dayListBox"></div>'),
            weekList = [], currentWeek = {},
            optionalDateMap = this.config.optionalDateMap,
            isAllOptional = this.config.isAllOptional,
            optionalDateConfig = this.config.optionalDateConfig,
            dayList = util.getDateListByMouth(dateObj.mouth, dateObj.year);

        mouthElem.data("yearMouth", dateObj.yearMouth);
        mouthElem.append(yearMonth).append(dayListBox);
        this.$calendarInfo.append(mouthElem);

        for (let i = 0; i < dayList.length; i++) {
            var date = dayList[i].date || '';
            var optionalDate = optionalDateMap[date];
            if (optionalDate || isAllOptional) {
                optionalDate = $.extend({}, optionalDateConfig, optionalDate, {optional: true});
            }
            var day = $.extend({}, TdCalendarWrap.DEFAULT_DATE_CONFIG, dayList[i], optionalDate);
            if (day.week === 0) {
                currentWeek = {
                    weekIndex: weekList.length,
                    $weekElem: $('<ul class="dayList"></ul>'),
                    dayList: [],
                    realDaySize: 0,
                };
            }
            var dayItem = $('<li class="dayItem"></li>');
            if (date) {
                this.setOneDayInfo(dayItem, date, day);
                currentWeek.realDaySize++;
            }
            currentWeek.$weekElem.append(dayItem);
            day.$dayElem = dayItem;
            currentWeek.dayList.push(day);

            if (day.week === 6) {
                dayListBox.append(currentWeek.$weekElem);
                // 到最后天重新赋值
                weekList.push(currentWeek);
                currentWeek = {};
            }
        }
        this.mouthList.push({
            yearMouth: dateObj.yearMouth,
            $mouthElem: mouthElem,
            weekList: weekList,
        });
    };

    // 在日历添加一月显示
    TdCalendarWrap.prototype.setOneDayInfo = function (dayItem, date, day) {
        dayItem.data("date", date);
        // 当前元素是否可选
        dayItem.addClass(day.optional ? OPTIONAL_DATE_CLASS : BAN_SELECTED_DATE_CLASS);
        // 上面展示的字
        dayItem.append('<span class="holidaySign">' + (day.upText || '') + '</span>');
        // 中间显示的字
        var dayNum = $('<span class="dayNum">' + (day[day.textKey] || day.day) + '</span>');
        if (this.config.isShowTodayText && util.getDateObj(nowDate).date === date) {
            dayNum.text("今天").addClass("todayText");
        }
        dayItem.append(dayNum)
        // 下面展示的字
        dayItem.append('<span class="tipsFont">' + (day.downText || '') + '</span>');
        // 判断是否可选并且是否已经选中
        if (day.optional && this.selectedDate.indexOf(date) !== -1) {
            // 当前元素已选中
            dayItem.addClass(SELECTED_DATE_CLASS);
            // 选中后修改上下对应的文字 没有则不修改
            if (day.selectUpText) dayItem.find(".holidaySign").text(day.selectUpText);
            if (day.selectDownText) dayItem.find(".tipsFont").text(day.selectDownText);
        }
        var that = this;
        dayItem.click(function (e) {
            e.stopPropagation();
            if (day.optional) {
                var className = $(this).attr("class");
                if (className.indexOf(SELECTED_DATE_CLASS) !== -1) {
                    // 取消选中
                    that.selectedDate.splice(that.selectedDate.indexOf(date), 1);
                    $(this).removeClass(SELECTED_DATE_CLASS);
                    // 设置原来上下对应的文字
                    $(this).find(".holidaySign").text(day.upText);
                    $(this).find(".tipsFont").text(day.downText);
                } else {
                    if (that.selectedDate.length < that.config.selectedSizeMax) {
                        // 选中
                        that.selectedDate.push(date);
                        $(this).addClass(SELECTED_DATE_CLASS);
                        // 选中后修改上下对应的文字 没有则不修改
                        if (day.selectUpText) $(this).find(".holidaySign").text(day.selectUpText);
                        if (day.selectDownText) $(this).find(".tipsFont").text(day.selectDownText);
                    } else {
                        if (that.config.selectedSizeExceed) {
                            that.config.selectedSizeExceed(day, that.selectedDate.length, that.config.selectedSizeMax, this)
                        }
                        return;
                    }
                }
                // 调用回调方法
                if (that.config.done) {
                    that.config.done(day, that.selectedDate, this);
                }
            }
        });
    };

    // 销毁
    TdCalendarWrap.prototype.destroy = function () {
        this.$elem.html(this.$elem_source.html()).attr('class', this.$elem_source.attr('class') || ''); // reset the class
    };

    $.fn.tdCalendarWrap = function (option) {
        var value;

        this.each(function () {
            var $this = $(this),
                data = $this.data(CALENDAR_WRAP_CLASS);

            if (typeof option === 'string') {
                if (!data) {
                    return;
                }
                switch (option) {
                    case "getSelectedDate":
                        value = data.selectedDate;
                        break;
                    case "destroy":
                        data.destroy();
                        $this.removeData(CALENDAR_WRAP_CLASS);
                        break;
                    default:
                        throw new Error("Unknown method: " + option);
                }
            } else if (typeof option === 'object') {
                var options = $.extend({}, TdCalendarWrap.DEFAULT_CONFIG, option);
                if (data) {
                    data.destroy();
                }
                $this.data(CALENDAR_WRAP_CLASS, new TdCalendarWrap(this, options));
            }
        });

        return typeof value === 'undefined' ? this : value;
    };

    // 用于计算 rem 和 px
    function getRem(pwidth, prem) {
        var html = document.getElementsByTagName("html")[0];
        var oWidth = document.body.clientWidth || document.documentElement.clientWidth;
        html.style.fontSize = oWidth / pwidth * prem + "px";
    }

    $(function () {
        //do something
        getRem(750, 100);
        window.onresize = function () {
            getRem(750, 100)
        };
    });

})(jQuery, window, document,);
